#include "Cache.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

// 创建缓存
Cache *create_cache(int max_size)
{
    if (max_size <= 0)
        return NULL;
    Cache *cache = (Cache *)malloc(sizeof(Cache));
    cache->table = create_table(max_size);
    cache->max_size = max_size;
    cache->current_size = 0;
    cache->lru_head = NULL;
    cache->lru_tail = NULL;
    cache->minHeap = NULL;
    cache->mode = 1;
    return cache;
}

// 释放LRU
void Destroy_LRU(Cache *cache)
{
    if (cache == NULL || cache->lru_head == NULL)
        return;
    LRUNode *current = cache->lru_head;
    while (current != NULL)
    {
        LRUNode *prev = current->prev;
        LRUNode *next = current->next;
        if (next == current)
            next = NULL;
        else
        {
            prev->next = next;
            next->prev = prev;
        }
        current->key = NULL;
        current->value = NULL;
        free(current);

        current = next;
    }
    cache->lru_head = NULL;
    cache->lru_tail = NULL;
}

// 释放缓存
void destroy_cache(Cache *cache)
{
    if (cache == NULL)
        return;
    Destroy_LRU(cache);
    destroy_table(cache->table);
    DestroyHeap(cache->minHeap);
    free(cache);
}

// 添加到LRU
void Add_to_LRU(Cache *cache, char *key, void *value, size_t value_size)
{
    LRUNode *node = (LRUNode *)malloc(sizeof(LRUNode));
    if (cache->lru_head == NULL)
    {
        cache->lru_head = (LRUNode *)malloc(sizeof(LRUNode));
        cache->lru_tail = cache->lru_head;
        cache->lru_head->next = cache->lru_head;
        cache->lru_head->prev = cache->lru_head;

        cache->lru_head->key = key;
        cache->lru_head->value = value;
        cache->lru_head->value_size = value_size;
    }
    else
    {
        // 头插
        node->prev = cache->lru_tail;
        node->next = cache->lru_head;
        cache->lru_tail->next = node;
        cache->lru_head->prev = node;
        cache->lru_tail = node;

        node->key = key;
        node->value = value;
        node->value_size = value_size;
    }
}

// 缓存中添加数据
void add_to_cache(Cache *cache, char *key, void *value, size_t value_size)
{
    // if(get(cache->table,key) != NULL)
    // {
    //     LRUNode* cur = cache->lru_head;
    //     while(cur->key!=key)cur = cur->next;
    //     move_to_head(cache,cur);
    //     return;
    // }
    if (cache->mode == 1)
    {
        if (cache->current_size >= cache->max_size)
        {
            remove_lru(cache, cache->lru_tail->key);
            remove_key(cache->table, key);
        }

        Add_to_LRU(cache, key, value, value_size);
    }
    else
    {
        if (cache->current_size >= cache->max_size)
        {
            ExtractMin(cache->minHeap);
            remove_key(cache->table, key);
            cache->current_size--;
        }

        HeapInsert(cache->minHeap, key);
    }

    insert(cache->table, key, value, value_size);
    cache->current_size++;
}

// 从文件中读取数据
bool read_from_file(Cache *cache, char *key, char **re_value)
{
    // 读入文件并返回
    int fd = open(key, O_RDONLY);
    if (fd == -1)
        return false;

    off_t file_size = lseek(fd, 0, SEEK_END);
    lseek(fd, 0, SEEK_SET);

    char *value = (char *)malloc(file_size + 1);
    memset(value, 0, file_size + 1);

    // 将文件的全部数据循环读到value中，知道读完为止
    ssize_t bytes_read;
    ssize_t total_bytes_read = 0;
    while ((bytes_read = read(fd, value + total_bytes_read, file_size - total_bytes_read)) > 0)
    {
        total_bytes_read += bytes_read;
    }

    if (bytes_read == -1 || total_bytes_read != file_size)
    {
        free(value);
        return NULL;
    }
    add_to_cache(cache, key, value, file_size + 1);
    *re_value = value;

    return true;
}

// 缓存中查找数据
char *get_from_cache(Cache *cache, char *key)
{
    printf("get_from_cache!!!!!!!!!!!!!!!\r\n");

    char *value = (char *)get(cache->table, key);

    if (value != NULL)
    {
        return value;
    }
    else // 缓存中不存在，从文件中读取
    {
        printf("缓存中不存在，从文件中读取!!!\r\n");
        if ((read_from_file(cache, key, &value)) == false)
        {
            printf("文件中不存在,key: %s\r\n", key);
            return NULL;
        }
        if(value == NULL)return NULL;
        return value;
    }
}

// 缓存中删除最久未用的数据
void remove_lru(Cache *cache, char *key)
{
    cache->lru_tail->key = NULL;
    cache->lru_tail->value = NULL;
    cache->lru_tail->value_size = 0;

    LRUNode *node = cache->lru_tail;

    if (cache->lru_tail == cache->lru_head)
    {
        cache->lru_head = NULL;
        cache->lru_tail = NULL;
    }
    else
    {
        node->prev->next = cache->lru_head;
        cache->lru_head->prev = node->prev;
        cache->lru_tail = node->prev;
    }
    free(node);
    cache->current_size--;
}

// 移动到LRU链头
void move_to_head(Cache *cache, LRUNode *node)
{
    if (node == cache->lru_head)
        return;

    node->prev->next = node->next;
    node->next->prev = node->prev;

    node->next = cache->lru_head;
    node->prev = cache->lru_head->prev;
    cache->lru_head->prev->next = node;
    cache->lru_head->prev = node;
    cache->lru_head = node;
}

// 转换为另一种调度模式
void SwitchToOther(Cache *cache)
{
    int size = cache->max_size;

    if (cache->mode == 1)
    {
        cache->minHeap = CreateMinHeap(size);
        if (cache->lru_head != NULL)
        {
            for (int i = 0; i < cache->current_size; i++)
            {
                if(cache->lru_tail->key == NULL)
                {
                    printf("LRU NULL key!!!\n\n");
                    break;
                }
                HeapInsert(cache->minHeap, cache->lru_tail->key);
                for (int j = i; j > 0; j++)
                    IncreaseFrequency(cache->minHeap, cache->lru_tail->key);
                remove_lru(cache, cache->lru_tail->key);
            }
        }
        Destroy_LRU(cache);
        cache->mode = 2;
        printf("Shift to LFU success!\r\n");
    }
    else
    {
        if (cache->minHeap != NULL)
        {
            for (int i = 0; i < cache->current_size; i++)
            {
                CacheNode minNode = ExtractMin(cache->minHeap);
                if(minNode.key == NULL)
                {
                    printf("LFU NULL key!!!\n\n");
                    break;
                }
                char *value = (char *)get(cache->table, minNode.key);
                //-----00000000
                Add_to_LRU(cache, minNode.key, value, strlen(value));
            }
        }
        DestroyHeap(cache->minHeap);
        cache->mode = 1;
        printf("Shift to LRU success!\r\n");
    }
}